package dataloader

// import graph gophers with your other imports
import (
	"context"
	"net/http"

	"mall/service/wpgql/api/internal/svc"

	"github.com/graph-gophers/dataloader"
)

type ctxKey string

const (
	loadersCtxKey = ctxKey("graph_dataloaders")
)

// DataLoader offers data loaders scoped to a context
type DataLoader struct {
	categoryLoader *dataloader.Loader
	menuItemLoader *dataloader.Loader
	userLoader     *dataloader.Loader
}

// NewDataLoader returns the instantiated Loaders struct for use in a request
func NewDataLoader(svcCtx *svc.ServiceContext) *DataLoader {
	return &DataLoader{
		categoryLoader: dataloader.NewBatchedLoader(NewCategoryBatcher(svcCtx).get),
		menuItemLoader: dataloader.NewBatchedLoader(NewMenuItemBatcher(svcCtx).get),
		userLoader:     dataloader.NewBatchedLoader(NewUserBatcher(svcCtx).get),
	}
}

// Middleware injects a DataLoader into the request context so it can be
// used later in the schema resolvers
func Middleware(loader *DataLoader) func(http.Handler) http.Handler {
	// return a middleware that injects the loader to the request context
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			ctx := context.WithValue(r.Context(), loadersCtxKey, loader)
			// and call the next with our new context
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}
}

func With(ctx context.Context, loader *DataLoader) context.Context {
	return context.WithValue(ctx, loadersCtxKey, loader)
}

// For returns the dataloader for a given context
func For(ctx context.Context) *DataLoader {
	loaders, ok := ctx.Value(loadersCtxKey).(*DataLoader)
	if !ok {
		return nil
	}

	return loaders
}
